
export type NetData = boolean | number | string;
//todo: 完善请求属性，满足更多需求。
export type HttpRequestContentType = "application/json" | "application/x-www-form-urlencoded" | "multipart/form-data";
export class HttpRequest {
    request: XMLHttpRequest = null;
    url: string = "";
    type: string = "GET";
    rspType: string = "json";
    contentType: HttpRequestContentType = "application/x-www-form-urlencoded";
    param: { [key: string]: NetData } = {};
    body: any = null;
    headers: { [key: string]: string } = {
        "Accept": "*/*",
    };
    timeout: number = 5000;
    async: boolean = true;

    static Post(url: string, body: any = null, contentType: HttpRequestContentType = "application/json", timeout = 5000) {
        let req = new HttpRequest(url);
        req.type = "POST";
        req.timeout = timeout;
        req.contentType = contentType;
        if (body) {
            req.setBody(body);
        }
        return req;
    }
    static Get(url: string, param: any = null, contentType: HttpRequestContentType = "application/x-www-form-urlencoded", timeout = 5000) {
        let req = new HttpRequest(url);
        req.type = "GET";
        req.timeout = timeout;
        req.contentType = contentType;
        if (param) {
            req.setParam(param);
        }
        return req;
    }
    constructor(url: string) {
        this.url = url;
    }

    setBody(body: any) {
        this.body = body;
        return this;
    }
    setParam(param: { [key: string]: NetData }) {
        this.param = param;
        return this;
    }
    setHeader(headers: { [key: string]: string }) {
        Object.assign(this.headers, headers);
        // this.headers = headers;
        return this;
    }

    async reqResponse() {
        let res = await this.req();
        return res.response;
    }
    async req() {
        let res = new HttpResponse();
        let request = new XMLHttpRequest();
        this.request = request;
        res.req = this;

        request.timeout = this.timeout;
        let reqUrl = this.url;

        var bodyData = null;
        if (this.body) {
            bodyData = {};
            Object.assign(bodyData, this.body);
        }

        if (this.param) {
            let paramData = {};
            Object.assign(paramData, this.param);
            if (bodyData && this.type === "POST" && this.contentType === "application/x-www-form-urlencoded") {
                Object.assign(paramData, this.body);
            }
            let sim = "?";
            for (let key in paramData) {
                reqUrl += sim + key + "=" + paramData[key];
                sim = "&";
            }
        }

        request.open(this.type, reqUrl, this.async);

        if (this.headers) {
            for (let key in this.headers) {
                request.setRequestHeader(key, this.headers[key]);
            }
            request.setRequestHeader("Content-Type", this.contentType);
        }

        if (bodyData) {
            switch (this.contentType) {
                case "application/json":
                    request.send(JSON.stringify(bodyData));
                    break;
                case "application/x-www-form-urlencoded":
                    request.send();
                    break;
                case "multipart/form-data":
                    request.send(bodyData);
                    break;
            }
        }
        else {
            request.send();
        }

        //todo: 这里可以去除await ,让 res 先返回。再通过res异步回调结果。
        await new Promise<void>(finish => {
            request.onreadystatechange = () => {
                if (request.readyState == 4) {
                    let status = request.status;
                    if (status >= 200 && status < 400) {
                        res.responseText = request.responseText;
                        if (this.rspType == "json") {
                            try {
                                res.response = JSON.parse(res.responseText);
                            }
                            catch (e) {
                                console.warn("Http::req, warn:", "返回的数据JSON解析失败", e);
                            }
                        }
                        res.status = HttpResponseStatus.Done;
                        finish();
                    }
                    else {
                        res.status = HttpResponseStatus.Fail;
                        finish();
                    }
                }
            };
            request.onerror = function () {
                res.status = HttpResponseStatus.Error;
                finish();
            };
            request.ontimeout = function () {
                res.status = HttpResponseStatus.Timeout;
                finish();
            };
        });

        return res;

    }
};

export enum HttpResponseStatus {
    Waitting,
    Done,
    Fail,
    Error,
    Timeout,
};

export class HttpResponse {
    req: HttpRequest = null;
    response = null;
    responseText = "";
    status = HttpResponseStatus.Waitting; //status >= 200 && status < 400
};
